home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / resample.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  34.4 KB  |  1,368 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <crtdbg.h>
  19.  
  20. #include <math.h>
  21.  
  22. #include "resample.h"
  23. #include "VBitmap.h"
  24. #include "cpuaccel.h"
  25.  
  26. ///////////////////////////////////////////////////////////////////////////
  27.  
  28. #if 0
  29.  
  30. __int64 last_upd;
  31. __int64 profile_column=0;
  32. __int64 profile_row=0;
  33. int profile_column_count=0;
  34. int profile_row_count=0;
  35.  
  36. #define PROFILE_START                                \
  37.         __int64 start_clock;                        \
  38.         __asm rdtsc                                    \
  39.         __asm mov dword ptr start_clock+0,eax        \
  40.         __asm mov dword ptr start_clock+4,edx
  41.  
  42. #define PROFILE_ADD(x)                                \
  43.         __int64 stop_clock;                            \
  44.         {__asm rdtsc                                    \
  45.         __asm mov dword ptr stop_clock+0,eax        \
  46.         __asm mov dword ptr stop_clock+4,edx}        \
  47.         profile_##x += stop_clock - start_clock;    \
  48.         profile_##x##_count ++;
  49.  
  50. static inline void stats_print() {
  51.     __int64 clk;
  52.  
  53.     __asm rdtsc
  54.     __asm mov dword ptr clk,eax
  55.     __asm mov dword ptr clk+4,edx
  56.  
  57.     if (clk - last_upd > 450000000) {
  58.         char buf[128];
  59.         last_upd = clk;
  60.  
  61.         if (profile_row_count && profile_column_count) {
  62.             sprintf(buf, "%I64d (%d), %I64d (%d) per scanline\n", profile_row/profile_row_count, profile_row_count, profile_column/profile_column_count, profile_column_count);
  63.             profile_row = profile_column = 0;
  64.             profile_row_count = profile_column_count = 0;
  65.             OutputDebugString(buf);
  66.         }
  67.     }
  68. }
  69. #else
  70. static inline void stats_print() {}
  71. #define PROFILE_START
  72. #define PROFILE_ADD(x)
  73. #endif
  74.  
  75. ///////////////////////////////////////////////////////////////////////////
  76.  
  77. extern "C" void __cdecl asm_resize_nearest(
  78.         Pixel32 *dst,
  79.         const Pixel32 *src,
  80.         long width,
  81.         PixDim height,
  82.         PixOffset dstpitch,
  83.         PixOffset srcpitch,
  84.         unsigned long xaccum,
  85.         unsigned long yaccum,
  86.         unsigned long xfrac,
  87.         unsigned long yfrac,
  88.         long xistep,
  89.         PixOffset yistep,
  90.         const Pixel32 *precopysrc,
  91.         unsigned long precopy,
  92.         const Pixel32 *postcopysrc,
  93.         unsigned long postcopy);
  94.  
  95. extern "C" void __cdecl asm_resize_bilinear(
  96.         void *dst,
  97.         void *src,
  98.         long w,
  99.         PixDim h,
  100.         PixOffset dstpitch,
  101.         PixOffset srcpitch,
  102.         unsigned long xaccum,
  103.         unsigned long yaccum,
  104.         unsigned long xfrac,
  105.         unsigned long yfrac,
  106.         long xistep,
  107.         PixOffset yistep,
  108.         Pixel32 *precopysrc,
  109.         unsigned long precopy,
  110.         Pixel32 *postcopysrc,
  111.         unsigned long postcopy);
  112.  
  113. extern "C" void asm_resize_interp_row_run(
  114.             void *dst,
  115.             const void *src,
  116.             unsigned long width,
  117.             __int64 xaccum,
  118.             __int64 x_inc);
  119.  
  120. extern "C" void asm_resize_interp_col_run(
  121.             void *dst,
  122.             const void *src1,
  123.             const void *src2,
  124.             unsigned long width,
  125.             unsigned long yaccum);
  126.  
  127. extern "C" void asm_resize_ccint(Pixel *dst, const Pixel *src1, const Pixel *src2, const Pixel *src3, const Pixel *src4, long count, long xaccum, long xint, const int *table);
  128. extern "C" void asm_resize_ccint_col(Pixel *dst, const Pixel *src1, const Pixel *src2, const Pixel *src3, const Pixel *src4, long count, const int *table);
  129. extern "C" void asm_resize_ccint_col_MMX(Pixel *dst, const Pixel *src1, const Pixel *src2, const Pixel *src3, const Pixel *src4, long count, const int *table);
  130.  
  131. extern "C" long resize_table_col_MMX(Pixel *out, const Pixel *const*in_table, const int *filter, int filter_width, PixDim w, long frac);
  132. extern "C" long resize_table_col_by2linear_MMX(Pixel *out, const Pixel *const*in_table, PixDim w);
  133. extern "C" long resize_table_col_by2cubic_MMX(Pixel *out, const Pixel *const*in_table, PixDim w);
  134.  
  135.  
  136. ///////////////////////////////////////////////////////////////////////////
  137.  
  138. //    void MakeCubic4Table(
  139. //        int *table,            pointer to 256x4 int array
  140. //        double A,            'A' value - determines characteristics
  141. //        mmx_table);            generate interleaved table
  142. //
  143. //    Generates a table suitable for cubic 4-point interpolation.
  144. //
  145. //    Each 4-int entry is a set of four coefficients for a point
  146. //    (n/256) past y[1].  They are in /16384 units.
  147. //
  148. //    A = -1.0 is the original VirtualDub bicubic filter, but it tends
  149. //    to oversharpen video, especially on rotates.  Use A = -0.75
  150. //    for a filter that resembles Photoshop's.
  151.  
  152.  
  153. void MakeCubic4Table(int *table, double A, bool mmx_table) throw() {
  154.     int i;
  155.  
  156.     for(i=0; i<256; i++) {
  157.         double d = (double)i / 256.0;
  158.         int y1, y2, y3, y4, ydiff;
  159.  
  160.         // Coefficients for all four pixels *must* add up to 1.0 for
  161.         // consistent unity gain.
  162.         //
  163.         // Two good values for A are -1.0 (original VirtualDub bicubic filter)
  164.         // and -0.75 (closely matches Photoshop).
  165.  
  166.         y1 = (int)floor(0.5 + (        +     A*d -       2.0*A*d*d +       A*d*d*d) * 16384.0);
  167.         y2 = (int)floor(0.5 + (+ 1.0             -     (A+3.0)*d*d + (A+2.0)*d*d*d) * 16384.0);
  168.         y3 = (int)floor(0.5 + (        -     A*d + (2.0*A+3.0)*d*d - (A+2.0)*d*d*d) * 16384.0);
  169.         y4 = (int)floor(0.5 + (                  +           A*d*d -       A*d*d*d) * 16384.0);
  170.  
  171.         // Normalize y's so they add up to 16384.
  172.  
  173.         ydiff = (16384 - y1 - y2 - y3 - y4)/4;
  174.         _ASSERT(ydiff > -16 && ydiff < 16);
  175.  
  176.         y1 += ydiff;
  177.         y2 += ydiff;
  178.         y3 += ydiff;
  179.         y4 += ydiff;
  180.  
  181.         if (mmx_table) {
  182.             table[i*4 + 0] = table[i*4 + 1] = (y2<<16) | (y1 & 0xffff);
  183.             table[i*4 + 2] = table[i*4 + 3] = (y4<<16) | (y3 & 0xffff);
  184.         } else {
  185.             table[i*4 + 0] = y1;
  186.             table[i*4 + 1] = y2;
  187.             table[i*4 + 2] = y3;
  188.             table[i*4 + 3] = y4;
  189.         }
  190.     }
  191. }
  192.  
  193. const int *GetStandardCubic4Table() throw() {
  194.     static int cubic4_tbl[256*4*2];
  195.  
  196.     if (!cubic4_tbl[1]) {
  197.         MakeCubic4Table(cubic4_tbl, -0.75, false);
  198.         MakeCubic4Table(cubic4_tbl+1024, -0.75, true);
  199.     }
  200.  
  201.     return cubic4_tbl;
  202. }
  203.  
  204. ///////////////////////////////////////////////////////////////////////////
  205.  
  206. void ResampleInfo::computeBounds(__int64 u, __int64 dudx, unsigned int dx, unsigned int kernel, unsigned long limit) {
  207.  
  208.     // The kernel length must always be even.  The precopy region covers all
  209.     // pixels where the kernel is completely off to the left; this occurs when
  210.     // u < -(kernel/2-1).
  211.     //
  212.     // We round the halfkernel value so that things work out for point-sampling
  213.     // kernels (k=1).
  214.  
  215.     __int64 halfkernel = ((kernel+1)>>1);
  216.     __int64 halfkernelm1 = halfkernel-1;
  217.  
  218.     if (u < (-halfkernelm1<<32)) {
  219.         clip.precopy = ((-halfkernelm1<<32) - u + (dudx-1)) / dudx;
  220.         if (clip.precopy > dx)
  221.             clip.precopy = dx;
  222.     } else
  223.         clip.precopy = 0;
  224.  
  225.     // Preclip region occurs anytime the left side of the kernel is off the
  226.     // border.  The kernel extends w/2-1 off the left, so that's how far we
  227.     // need to step....
  228.     //
  229.     // Preclip regions don't occur with point sampling.
  230.  
  231.     if (kernel>1 && u < (halfkernelm1<<32)) {
  232.         clip.preclip = ((halfkernelm1<<32) - u + (dudx-1)) / dudx;
  233.         if (clip.preclip > dx)
  234.             clip.preclip = dx;
  235.     
  236.         clip.preclip -= clip.precopy;
  237.     } else
  238.         clip.preclip = 0;
  239.  
  240.     // Postcopy region occurs if we step onto or past (limit + kernel/2 - 2).
  241.  
  242.     __int64 dulimit = u + dudx * (dx-1);
  243.  
  244.     if ((long)(dulimit>>32) >= (long)(limit+(long)(halfkernelm1-1))) {
  245.         clip.postcopy = dx - ((((limit + halfkernelm1 - 1)<<32) - u - 1) / dudx + 1);
  246.  
  247.         if (clip.postcopy > dx)
  248.             clip.postcopy = dx;
  249.     } else
  250.         clip.postcopy = 0;
  251.  
  252.     // Postclip region occurs if we step onto or past (limit - kernel/2 + 1).
  253.     //
  254.     // Postclip regions don't occur with point sampling.
  255.  
  256.     if (kernel>1 && (long)(dulimit>>32) >= (long)(limit-(long)halfkernelm1)) {
  257.         clip.postclip = dx - ((((limit - halfkernelm1)<<32) - u - 1) / dudx + 1);
  258.  
  259.         if (clip.postclip > dx)
  260.             clip.postclip = dx;
  261.  
  262.         clip.postclip -= clip.postcopy;
  263.     } else
  264.         clip.postclip = 0;
  265.  
  266.     clip.unclipped = dx - (clip.precopy + clip.preclip + clip.postcopy + clip.postclip);
  267.  
  268.     clip.allclip = 0;
  269.     if (clip.unclipped < 0) {
  270.         clip.allclip = dx - (clip.precopy + clip.postcopy);
  271.         clip.postclip = clip.preclip = 0;
  272.         clip.unclipped = 0;
  273.     }
  274.  
  275.     clip.preclip2 = clip.postclip2 = 0;
  276. }
  277.  
  278. void ResampleInfo::computeBounds4(__int64 u, __int64 dudx, unsigned int dx, unsigned long limit) {
  279.     // The kernel length must always be even.  The precopy region covers all
  280.     // pixels where the kernel is completely off to the left; this occurs when
  281.     // u < -(kernel/2-1).
  282.     //
  283.     // We round the halfkernel value so that things work out for point-sampling
  284.     // kernels (k=1).
  285.  
  286.     const __int64 halfkernel = 2;
  287.     const __int64 halfkernelm1 = 1;
  288.  
  289.     if (u < (-halfkernelm1<<32))
  290.         clip.precopy = ((-halfkernelm1<<32) - u + (dudx-1)) / dudx;
  291.     else
  292.         clip.precopy = 0;
  293.  
  294.     // Preclip region occurs anytime the left side of the kernel is off the
  295.     // border.  The kernel extends 1 off the left, so that's how far we
  296.     // need to step....
  297.  
  298.     // Preclip2: [a b|c d]        pass: u >= 0.0
  299.  
  300.     if (u < (halfkernelm1<<32))
  301.         clip.preclip2 = (-u + (dudx-1)) / dudx - clip.precopy;
  302.     else
  303.         clip.preclip2 = 0;
  304.  
  305.     // Preclip: [a|b c d]        pass: u >= 1.0
  306.  
  307.     if (u < (halfkernelm1<<32))
  308.         clip.preclip = ((halfkernelm1<<32) - u + (dudx-1)) / dudx - (clip.precopy+clip.preclip2);
  309.     else
  310.         clip.preclip = 0;
  311.  
  312.     // Postcopy region occurs if we step onto or past (limit).
  313.  
  314.     __int64 dulimit = u + dudx * (dx-1);
  315.  
  316.     if ((long)(dulimit>>32) >= (long)limit)
  317.         clip.postcopy = dx - ((((__int64)limit<<32) - u - 1) / dudx + 1);
  318.     else
  319.         clip.postcopy = 0;
  320.  
  321.     // Postclip2: [a b|c d]        pass: u < limit-1
  322.  
  323.     if ((long)(dulimit>>32) >= (long)(limit-(long)halfkernelm1))
  324.         clip.postclip2 = dx - clip.postcopy - ((((__int64)(limit-1)<<32) - u - 1) / dudx + 1);
  325.     else
  326.         clip.postclip2 = 0;
  327.  
  328.     // Postclip: [a b c|d]        pass: u < limit-2
  329.  
  330.     if ((long)(dulimit>>32) >= (long)(limit-(long)halfkernelm1-1))
  331.         clip.postclip = dx - clip.postcopy - clip.postclip2 - ((((__int64)(limit-2)<<32) - u - 1) / dudx + 1);
  332.     else
  333.         clip.postclip = 0;
  334.  
  335.     clip.unclipped = dx - (clip.precopy + clip.preclip2 + clip.preclip + clip.postcopy + clip.postclip + clip.postclip2);
  336.  
  337.     clip.allclip = 0;
  338.     if (clip.unclipped < 0) {
  339.         clip.allclip = dx - (clip.precopy + clip.postcopy);
  340.  
  341.         clip.preclip = clip.preclip2 = clip.postclip2 = clip.postclip = 0;
  342.         clip.unclipped = 0;
  343.     }
  344. }
  345.  
  346. bool ResampleInfo::init(double x, double dx, double u, double du, unsigned long xlimit, unsigned long ulimit, int kw, bool bMapCorners, bool bClip4) {
  347.     
  348.     // Undo any destination flips.
  349.     
  350.     if (dx < 0) {
  351.         x += dx;
  352.         dx = -dx;
  353.     }
  354.     
  355.     // Precondition: destination area must not be empty.
  356.     // Compute slopes.
  357.  
  358.    double dudx;
  359.     
  360.    if (bMapCorners) {
  361.        if (dx <= 1.0)
  362.            return false;
  363.            
  364.       dudx = (du > 1.0 ? du - 1.0 : du < 1.0 ? du + 1.0 : 0.0)  / (dx-1.0);
  365.    } else {
  366.        if (dx <= 0.0)
  367.            return false;
  368.            
  369.        dudx = du / dx;
  370.     
  371.        // Prestep destination pixels so that we step on pixel centers.  We're going
  372.        // to be using Direct3D's screen-space system, where pixels sit on integer
  373.        // coordinates and the fill-convention is top-left.  However, OpenGL's system
  374.        // is easier to use from the client point of view, so we'll subtract 0.5 from
  375.        // all coordinates to compensate.  This means that a 1:1 blit of an 8x8
  376.        // rectangle should be (0,0)-(8,8) in both screen and texture space.
  377.  
  378.        x -= 0.5;
  379.        u -= 0.5;
  380.    }
  381.  
  382.     // Compute integer destination rectangle.
  383.  
  384.     x1_int = ceil(x);
  385.     dx_int = ceil(x + dx) - x;
  386.  
  387.     // Clip destination rectangle.
  388.  
  389.     if (x1_int<0) {
  390.         dx_int -= x1_int;
  391.         x1_int = 0;
  392.     }
  393.  
  394.     if (x1_int+dx_int > xlimit)
  395.         dx_int = xlimit - x1_int;
  396.  
  397.     if (dx_int<=0)
  398.         return false;
  399.  
  400.     // Prestep source.
  401.  
  402.     double prestep;
  403.  
  404.     prestep = (x1_int - x) * dudx;
  405.     u += prestep;
  406.     du -= prestep;
  407.  
  408.     // Compute integer step values.  Rounding toward zero is usually a pretty
  409.     // safe bet.
  410.  
  411.     dudx_int.v = (__int64)(4294967296.0 * dudx);
  412.  
  413.     // Compute starting sampling coordinate.
  414.  
  415.     u0_int.v = (__int64)((u + u + dudx - 1.0)*2147483648.0);
  416.  
  417.     // Compute clipping parameters.
  418.  
  419.     if (bClip4)
  420.         computeBounds4(u0_int.v, dudx_int.v, dx_int, ulimit);
  421.     else
  422.         computeBounds(u0_int.v, dudx_int.v, dx_int, kw, ulimit);
  423.  
  424.     // Advance source to beginning of clipped region.
  425.  
  426.     u0_int.v += dudx_int.v * clip.precopy;
  427.  
  428.     return true;
  429. }
  430.  
  431. extern "C" long resize_table_row_MMX(Pixel *out, const Pixel *in, const int *filter, int filter_width, PixDim w, long accum, long frac);
  432. extern "C" long resize_table_row_protected_MMX(Pixel *out, const Pixel *in, const int *filter, int filter_width, PixDim w, long accum, long frac, long limit);
  433. extern "C" long resize_table_row_by2linear_MMX(Pixel *out, const Pixel *in, PixDim w);
  434. extern "C" long resize_table_row_by2cubic_MMX(Pixel *out, const Pixel *in, PixDim w, unsigned long accum, unsigned long fstep, unsigned long istep);
  435.  
  436. void resize_table_row(Pixel *out, const Pixel *in, const int *filter, int filter_width, PixDim w, PixDim w_left, PixDim w_right, PixDim w_all, PixDim w2, long accum, long frac, int accel_code) {
  437.     const Pixel *in0 = in;
  438.  
  439.     in -= filter_width/2 - 1;
  440.  
  441.     if (MMX_enabled) {
  442.         if (w_all > 0) {
  443.             accum = resize_table_row_protected_MMX(out, in0, filter, filter_width, w_all, accum - ((filter_width/2-1)<<16), frac, w2-1) + ((filter_width/2-1)<<16);
  444.             out += w_all;
  445.             return;
  446.         }
  447.  
  448.         if (w_left > 0) {
  449.             accum = resize_table_row_protected_MMX(out, in0, filter, filter_width, w_left, accum - ((filter_width/2-1)<<16), frac, w2-1) + ((filter_width/2-1)<<16);
  450.             out += w_left;
  451.         }
  452.  
  453.         if (w > 0) {
  454.             PROFILE_START
  455.  
  456. /*            if (accel_code == ACCEL_BICUBICBY2) {
  457.                 resize_table_row_by2cubic_MMX(out, in + (accum>>16), w, accum<<16, frac<<16, frac>>16);
  458.  
  459.                 accum += frac*w;
  460.             } else if (accel_code == ACCEL_BILINEARBY2) {
  461.                 resize_table_row_by2linear_MMX(out, in + (accum>>16), w);
  462.  
  463.                 accum += frac*w;
  464.             } else*/
  465.                 accum = resize_table_row_MMX(out, in, filter, filter_width, w, accum, frac);
  466.  
  467.             PROFILE_ADD(row)
  468.  
  469.             out += w;
  470.         }
  471.  
  472.         if (w_right > 0)
  473.             resize_table_row_protected_MMX(out, in0, filter, filter_width, w_right, accum - ((filter_width/2-1)<<16), frac, w2-1);
  474.     } else {
  475.         const Pixel *in_bottom, *in_top;
  476.         in_bottom = in0;
  477.         in_top = in0 + w2;
  478.  
  479.         if (w_all > 0) {
  480.             do {
  481.                 int x, r, g, b;
  482.                 const Pixel *in2;
  483.                 const int *filter2;
  484.  
  485.                 x = filter_width;
  486.                 in2 = in + (accum>>16);
  487.                 filter2 = filter + ((accum>>8) & 255)*filter_width;
  488.                 r = g = b = 0;
  489.  
  490.                 do {
  491.                     Pixel c;
  492.                     int a;
  493.  
  494.                     if (in2 < in_bottom)
  495.                         c = *in_bottom;
  496.                     else if (in >= in_top)
  497.                         c =  in_top[-1];
  498.                     else
  499.                         c =  *in2;
  500.                     ++in2;
  501.  
  502.                     a = *filter2++;
  503.  
  504.                     r += ((c>>16)&255) * a;
  505.                     g += ((c>> 8)&255) * a;
  506.                     b += ((c    )&255) * a;
  507.  
  508.                 } while(--x);
  509.  
  510.                 r = (r + 8192)>>14;
  511.                 g = (g + 8192)>>14;
  512.                 b = (b + 8192)>>14;
  513.  
  514.                 if (r<0) r=0; else if (r>255) r=255;
  515.                 if (g<0) g=0; else if (g>255) g=255;
  516.                 if (b<0) b=0; else if (b>255) b=255;
  517.  
  518.                 *out++ = (r<<16) + (g<<8) + b;
  519.  
  520.                 accum += frac;
  521.  
  522.             } while(--w_all);
  523.  
  524.             return;
  525.         }
  526.  
  527.         if (w_left > 0)
  528.             do {
  529.                 int x, r, g, b;
  530.                 const Pixel *in2;
  531.                 const int *filter2;
  532.  
  533.                 x = filter_width;
  534.                 in2 = in + (accum>>16);
  535.                 filter2 = filter + ((accum>>8) & 255)*filter_width;
  536.                 r = g = b = 0;
  537.  
  538.                 do {
  539.                     Pixel c;
  540.                     int a;
  541.  
  542.                     if (in2 < in_bottom)
  543.                         c = *in_bottom;
  544.                     else
  545.                         c =  *in2;
  546.                     ++in2;
  547.  
  548.                     a = *filter2++;
  549.  
  550.                     r += ((c>>16)&255) * a;
  551.                     g += ((c>> 8)&255) * a;
  552.                     b += ((c    )&255) * a;
  553.  
  554.                 } while(--x);
  555.  
  556.                 r = (r + 8192)>>14;
  557.                 g = (g + 8192)>>14;
  558.                 b = (b + 8192)>>14;
  559.  
  560.                 if (r<0) r=0; else if (r>255) r=255;
  561.                 if (g<0) g=0; else if (g>255) g=255;
  562.                 if (b<0) b=0; else if (b>255) b=255;
  563.  
  564.                 *out++ = (r<<16) + (g<<8) + b;
  565.  
  566.                 accum += frac;
  567.  
  568.             } while(--w_left);
  569.  
  570.         if (w > 0)
  571.             do {
  572.                 int x, r, g, b;
  573.                 const Pixel *in2;
  574.                 const int *filter2;
  575.  
  576.                 x = filter_width;
  577.                 in2 = in + (accum>>16);
  578.                 filter2 = filter + ((accum>>8) & 255)*filter_width;
  579.                 r = g = b = 0;
  580.                 do {
  581.                     Pixel c;
  582.                     int a;
  583.  
  584.                     c =  *in2++;
  585.                     a = *filter2++;
  586.  
  587.                     r += ((c>>16)&255) * a;
  588.                     g += ((c>> 8)&255) * a;
  589.                     b += ((c    )&255) * a;
  590.  
  591.                 } while(--x);
  592.  
  593.                 r = (r + 8192)>>14;
  594.                 g = (g + 8192)>>14;
  595.                 b = (b + 8192)>>14;
  596.  
  597.                 if (r<0) r=0; else if (r>255) r=255;
  598.                 if (g<0) g=0; else if (g>255) g=255;
  599.                 if (b<0) b=0; else if (b>255) b=255;
  600.  
  601.                 *out++ = (r<<16) + (g<<8) + b;
  602.  
  603.                 accum += frac;
  604.             } while(--w);
  605.  
  606.         if (w_right > 0) do {
  607.             int x, r, g, b;
  608.             const Pixel *in2;
  609.             const int *filter2;
  610.  
  611.             x = filter_width;
  612.             in2 = in + (accum>>16);
  613.             filter2 = filter + ((accum>>8) & 255)*filter_width;
  614.             r = g = b = 0;
  615.  
  616.             do {
  617.                 Pixel c;
  618.                 int a;
  619.  
  620.                 if (in2 >= in_top)
  621.                     c = in_top[-1];
  622.                 else
  623.                     c =  *in2++;
  624.  
  625.                 a = *filter2++;
  626.  
  627.                 r += ((c>>16)&255) * a;
  628.                 g += ((c>> 8)&255) * a;
  629.                 b += ((c    )&255) * a;
  630.  
  631.             } while(--x);
  632.  
  633.             r = (r + 8192)>>14;
  634.             g = (g + 8192)>>14;
  635.             b = (b + 8192)>>14;
  636.  
  637.             if (r<0) r=0; else if (r>255) r=255;
  638.             if (g<0) g=0; else if (g>255) g=255;
  639.             if (b<0) b=0; else if (b>255) b=255;
  640.  
  641.             *out++ = (r<<16) + (g<<8) + b;
  642.  
  643.             accum += frac;
  644.  
  645.         } while(--w_right);
  646.     }
  647. }
  648.  
  649. ///////////////////////////////////////////////////////////////////////////
  650.  
  651. void resize_table_col(Pixel *out, const Pixel *const*in_rows, int *filter, int filter_width, PixDim w, long frac, int accel_code) {
  652.     int x;
  653.  
  654.     if (MMX_enabled) {
  655.         PROFILE_START
  656.  
  657. /*        if (accel_code == ACCEL_BICUBICBY2)
  658.             resize_table_col_by2cubic_MMX(out, in_rows, w);
  659.         else if (accel_code == ACCEL_BILINEARBY2)
  660.             resize_table_col_by2linear_MMX(out, in_rows, w);
  661.         else*/
  662.             resize_table_col_MMX(out, in_rows, filter, filter_width, w, frac);
  663.  
  664.         PROFILE_ADD(column)
  665.  
  666.         return;
  667.     }
  668.  
  669.     x = 0;
  670.     do {
  671.         int x2, r, g, b;
  672.         const Pixel *const *in_row;
  673.         const int *filter2;
  674.  
  675.         x2 = filter_width;
  676.         in_row = in_rows;
  677.         filter2 = filter + frac*filter_width;
  678.         r = g = b = 0;
  679.         do {
  680.             Pixel c;
  681.             int a;
  682.  
  683.             c =  (*in_row++)[x];
  684.             a = *filter2++;
  685.  
  686.             r += ((c>>16)&255) * a;
  687.             g += ((c>> 8)&255) * a;
  688.             b += ((c    )&255) * a;
  689.  
  690.         } while(--x2);
  691.  
  692.         r = (r + 8192)>>14;
  693.         g = (g + 8192)>>14;
  694.         b = (b + 8192)>>14;
  695.  
  696.         if (r<0) r=0; else if (r>255) r=255;
  697.         if (g<0) g=0; else if (g>255) g=255;
  698.         if (b<0) b=0; else if (b>255) b=255;
  699.  
  700.         *out++ = (r<<16) + (g<<8) + b;
  701.     } while(++x < w);
  702. }
  703.  
  704.  
  705. #define RED(x) ((signed long)((x)>>16)&255)
  706. #define GRN(x) ((signed long)((x)>> 8)&255)
  707. #define BLU(x) ((signed long)(x)&255)
  708.  
  709. static inline Pixel cc(const Pixel *yptr, const int *tbl) {
  710.     const Pixel y1 = yptr[0];
  711.     const Pixel y2 = yptr[1];
  712.     const Pixel y3 = yptr[2];
  713.     const Pixel y4 = yptr[3];
  714.     long red, grn, blu;
  715.  
  716.     red = RED(y1)*tbl[0] + RED(y2)*tbl[1] + RED(y3)*tbl[2] + RED(y4)*tbl[3];
  717.     grn = GRN(y1)*tbl[0] + GRN(y2)*tbl[1] + GRN(y3)*tbl[2] + GRN(y4)*tbl[3];
  718.     blu = BLU(y1)*tbl[0] + BLU(y2)*tbl[1] + BLU(y3)*tbl[2] + BLU(y4)*tbl[3];
  719.  
  720.     if (red<0) red=0; else if (red>4194303) red=4194303;
  721.     if (grn<0) grn=0; else if (grn>4194303) grn=4194303;
  722.     if (blu<0) blu=0; else if (blu>4194303) blu=4194303;
  723.  
  724.     return ((red<<2) & 0xFF0000) | ((grn>>6) & 0x00FF00) | (blu>>14);
  725. }
  726.  
  727. #undef RED
  728. #undef GRN
  729. #undef BLU
  730.  
  731. void cc_row(Pixel *dst, const Pixel *src, long w, long xs_left2, long xs_left, long xs_right, long xs_right2, long xaccum, long xinc, const int *table) {
  732.  
  733.     src += xaccum>>16;
  734.     xaccum&=0xffff;
  735.  
  736.     if (xs_left2) {
  737.         Pixel x[4] = { src[1], src[1], src[1], src[2] };
  738.  
  739.         do {
  740.             *dst++ = cc(x, table + 4*((xaccum>>8)&0xff));
  741.  
  742.             xaccum += xinc;
  743.             src += xaccum>>16;
  744.             xaccum&=0xffff;
  745.         } while(--xs_left2);
  746.     }
  747.  
  748.     if (xs_left) {
  749.         Pixel x[4] = { src[0], src[0], src[1], src[2] };
  750.  
  751.         do {
  752.             *dst++ = cc(x, table + 4*((xaccum>>8)&0xff));
  753.  
  754.             xaccum += xinc;
  755.             src += xaccum>>16;
  756.             xaccum&=0xffff;
  757.         } while(--xs_left);
  758.     }
  759.  
  760.     if (!MMX_enabled) {
  761.         do {
  762.             *dst++ = cc(src-1, table + 4*((xaccum>>8)&0xff));
  763.  
  764.             xaccum += xinc;
  765.             src += xaccum>>16;
  766.             xaccum&=0xffff;
  767.         } while(--w);
  768.     } else {
  769.         asm_resize_ccint(dst, src-1, src, src+1, src+2, w, xaccum, xinc, table+1024);
  770.  
  771.         dst += w;
  772.  
  773.         xaccum += xinc*w;
  774.         src += xaccum>>16;
  775.         xaccum &= 0xffff;
  776.     }
  777.  
  778.     if (xs_right) do {
  779.         Pixel x[4] = { src[-1], src[0], src[1], src[1] };
  780.  
  781.         *dst++ = cc(x, table + 4*((xaccum>>8)&0xff));
  782.  
  783.         xaccum += xinc;
  784.         src += xaccum>>16;
  785.         xaccum&=0xffff;
  786.     } while(--xs_right);
  787.  
  788.     if (xs_right2) do {
  789.         Pixel x[4] = { src[-1], src[0], src[0], src[0] };
  790.  
  791.         *dst++ = cc(x, table + 4*((xaccum>>8)&0xff));
  792.  
  793.         xaccum += xinc;
  794.         src += xaccum>>16;
  795.         xaccum&=0xffff;
  796.     } while(--xs_right2);
  797. }
  798.  
  799. void cc_row_protected(Pixel *dst, const Pixel *src_low, const Pixel *src_high, long w, long xaccum, long xinc, const int *table) {
  800.     const Pixel32 *src = src_low + (xaccum>>16);
  801.  
  802.     xaccum&=0xffff;
  803.  
  804.     if (w) {
  805.         do {
  806.             Pixel32 x[4];
  807.  
  808.             if (src-1 < src_low)
  809.                 x[0] = src_low[0];
  810.             else if (src-1 >= src_high)
  811.                 x[0] = src_high[-1];
  812.             else
  813.                 x[0] = src[-1];
  814.  
  815.             if (src < src_low)
  816.                 x[1] = src_low[0];
  817.             else if (src >= src_high)
  818.                 x[1] = src_high[-1];
  819.             else
  820.                 x[1] = src[0];
  821.  
  822.             if (src+1 < src_low)
  823.                 x[2] = src_low[0];
  824.             else if (src+1 >= src_high)
  825.                 x[2] = src_high[-1];
  826.             else
  827.                 x[2] = src[+1];
  828.  
  829.             if (src+2 < src_low)
  830.                 x[3] = src_low[0];
  831.             else if (src+2 >= src_high)
  832.                 x[3] = src_high[-1];
  833.             else
  834.                 x[3] = src[+2];
  835.  
  836.             *dst++ = cc(x, table + 4*((xaccum>>8)&0xff));
  837.  
  838.             xaccum += xinc;
  839.             src += xaccum>>16;
  840.             xaccum&=0xffff;
  841.         } while(--w);
  842.     }
  843.  
  844. }
  845. ///////////////////////////////////////////////////////////////////////////
  846.  
  847. Resampler::Resampler()
  848.     : xtable(0)
  849.     , ytable(0)
  850.     , rows(0)
  851.     , rowmem(0)
  852. {
  853. }
  854.  
  855. Resampler::~Resampler() {
  856.     Free();
  857. }
  858.  
  859. void Resampler::Init(eFilter horiz_filt, eFilter vert_filt, double dx, double dy, double sx, double sy) {
  860.  
  861.     // Delete any previous allocations.
  862.  
  863.     Free();
  864.  
  865.     this->srcw = sx;
  866.     this->srch = sy;
  867.     this->dstw = dx;
  868.     this->dsth = dy;
  869.  
  870.     // Compute number of rows we need to store.
  871.     //
  872.     // point:            none.
  873.     // linearinterp:    2 if horiz != linearinterp
  874.     // cubicinterp:        4
  875.     // lineardecimate:    variable
  876.     // cubicdecimate:    variable
  877.     //
  878.     // Create tables and get interpolation values.
  879.  
  880.     rowcount = 0;
  881.     ubias = vbias = 1.0 / 512.0;
  882.  
  883.     switch(horiz_filt) {
  884.     case eFilter::kPoint:
  885.         xfiltwidth = 1;
  886.         ubias = 1.0 / 2.0;
  887.         break;
  888.     case eFilter::kLinearDecimate:
  889.         if (sx > dx) {
  890.             xtable = _CreateLinearDecimateTable(dx, sx, xfiltwidth);
  891.             break;
  892.         }
  893.         horiz_filt = eFilter::kLinearInterp;
  894.     case eFilter::kLinearInterp:
  895.         xfiltwidth = 2;
  896.         break;
  897.     case eFilter::kCubicDecimate:
  898.         if (sx > dx) {
  899.             xtable = _CreateCubicDecimateTable(dx, sx, xfiltwidth);
  900.             break;
  901.         }
  902.         horiz_filt = eFilter::kCubicInterp;
  903.     case eFilter::kCubicInterp:
  904.         GetStandardCubic4Table();
  905.         xfiltwidth = 4;
  906.         break;
  907.     }
  908.  
  909.     switch(vert_filt) {
  910.     case eFilter::kPoint:
  911.         if (horiz_filt != eFilter::kPoint)
  912.             rowcount = 1;
  913.         yfiltwidth = 1;
  914.         vbias = 1.0 / 2.0;
  915.         break;
  916.     case eFilter::kLinearDecimate:
  917.         if (sy > dy) {
  918.             ytable = _CreateLinearDecimateTable(dy, sy, yfiltwidth);
  919.             rowcount = yfiltwidth;
  920.             break;
  921.         }
  922.         vert_filt = eFilter::kLinearInterp;
  923.     case eFilter::kLinearInterp:
  924.         if (horiz_filt != eFilter::kLinearInterp)
  925.             rowcount = 2;
  926.         else
  927.             vbias = 1.0/32.0;
  928.         yfiltwidth = 2;
  929.         break;
  930.     case eFilter::kCubicDecimate:
  931.         if (sy > dy) {
  932.             ytable = _CreateCubicDecimateTable(dy, sy, yfiltwidth);
  933.             rowcount = yfiltwidth;
  934.             break;
  935.         }
  936.         vert_filt = eFilter::kCubicInterp;
  937.     case eFilter::kCubicInterp:
  938.         GetStandardCubic4Table();
  939.         yfiltwidth = 4;
  940.         rowcount = 4;
  941.         break;
  942.     }
  943.  
  944.     // Allocate the rows.
  945.  
  946.     if (rowcount) {
  947.         rowpitch = ((int)ceil(dx)+1)&~1;
  948.  
  949.         rowmem = new Pixel32[rowpitch * rowcount];
  950.         rows = new Pixel32*[rowcount * 2];
  951.     }
  952.  
  953.     this->nHorizFilt = horiz_filt;
  954.     this->nVertFilt = vert_filt;
  955. }
  956.  
  957. void Resampler::Free() {
  958.     delete[] xtable;
  959.     delete[] ytable;
  960.     delete[] rowmem;
  961.     delete[] rows;
  962.  
  963.     xtable = ytable = NULL;
  964.     rowmem = NULL;
  965.     rows = NULL;
  966. }
  967.  
  968. void Resampler::_DoRow(Pixel32 *dstp, const Pixel32 *srcp, long srcw) {
  969.     int x;
  970.  
  971.     for(x=0; x < horiz.clip.precopy; ++x)
  972.         dstp[x] = srcp[0];
  973.  
  974.     if (xtable)
  975.         resize_table_row(
  976.             dstp + horiz.clip.precopy,
  977.             srcp,
  978.             xtable,
  979.             xfiltwidth,
  980.             horiz.clip.unclipped,
  981.             horiz.clip.preclip,
  982.             horiz.clip.postclip,
  983.             horiz.clip.allclip,
  984.             srcw,
  985.             (long)(horiz.u0_int.v >> 16),
  986.             (long)(horiz.dudx_int.v >> 16),
  987.             0);
  988.     else switch(nHorizFilt) {
  989.         case eFilter::kPoint:
  990.             asm_resize_nearest(
  991.                     dstp + horiz.clip.precopy + horiz.clip.unclipped,            // destination pointer, right side
  992.                     srcp + horiz.u0_int.hi,
  993.                     -horiz.clip.unclipped*4,        // -width*4
  994.                     1,                                // height
  995.                     0,                                // dstpitch
  996.                     0,                                // srcpitch
  997.                     horiz.u0_int.lo,                // xaccum
  998.                     0,                                // yaccum
  999.                     horiz.dudx_int.lo,                // xfrac
  1000.                     0,                                // yfrac
  1001.                     horiz.dudx_int.hi,                // xinc
  1002.                     0,                                // yinc
  1003.                     srcp,
  1004.                     horiz.clip.precopy,                // precopy
  1005.                     srcp + srcw - 1,
  1006.                     horiz.clip.postcopy                // postcopy
  1007.                     );
  1008.             break;
  1009.  
  1010.         case eFilter::kLinearInterp:
  1011.             asm_resize_interp_row_run(
  1012.                 dstp + horiz.clip.precopy,
  1013.                 srcp,
  1014.                 horiz.clip.unclipped,
  1015.                 horiz.u0_int.v,
  1016.                 horiz.dudx_int.v);
  1017.             break;
  1018.  
  1019.         case eFilter::kCubicInterp:
  1020.             if (horiz.clip.allclip)
  1021.                 cc_row_protected(dstp + horiz.clip.precopy,
  1022.                     srcp, srcp+srcw,
  1023.                     horiz.clip.allclip,
  1024.                     (long)(horiz.u0_int.v >> 16),
  1025.                     (long)(horiz.dudx_int.v >> 16),
  1026.                     GetStandardCubic4Table());
  1027.             else
  1028.                 cc_row(dstp + horiz.clip.precopy,
  1029.                     srcp,
  1030.                     horiz.clip.unclipped,
  1031.                     horiz.clip.preclip2,
  1032.                     horiz.clip.preclip,
  1033.                     horiz.clip.postclip,
  1034.                     horiz.clip.postclip2,
  1035.                     (long)(horiz.u0_int.v >> 16),
  1036.                     (long)(horiz.dudx_int.v >> 16),
  1037.                     GetStandardCubic4Table());
  1038.             break;
  1039.     };
  1040.  
  1041.     for(x=0; x < horiz.clip.postcopy; ++x)
  1042.         dstp[horiz.dx_int - horiz.clip.postcopy + x] = srcp[srcw-1];
  1043. }
  1044.  
  1045.  
  1046. bool Resampler::Process(const VBitmap *dst, double _x2, double _y2, const VBitmap *src, double _x1, double _y1, bool bMapCorners) throw() {
  1047.  
  1048.     // No format conversions!!
  1049.  
  1050.     if (src->depth != dst->depth)
  1051.         return false;
  1052.  
  1053.     // Right now, only do 32-bit stretch.  (24-bit is a pain, 16-bit is slow.)
  1054.  
  1055.     if (dst->depth != 32)
  1056.         return false;
  1057.  
  1058.     // Compute clipping parameters.
  1059.  
  1060.     if (!horiz.init(_x2, dstw, _x1 + ubias, srcw, dst->w, src->w, xfiltwidth, bMapCorners, nHorizFilt == eFilter::kCubicInterp))
  1061.         return false;
  1062.  
  1063.     if (!vert.init(_y2, dsth, _y1 + vbias, srch, dst->h, src->h, yfiltwidth, bMapCorners, false))
  1064.         return false;
  1065.  
  1066.     long dx = horiz.dx_int;
  1067.     long dy = vert.dx_int;
  1068.  
  1069.     // Call texturing routine.
  1070.  
  1071.     Pixel32 *dstp = dst->Address32(horiz.x1_int, vert.x1_int);
  1072.     Pixel32 *srcp;
  1073.  
  1074.     int xprecopy    = horiz.clip.precopy;
  1075.     int xpreclip2    = horiz.clip.preclip2;
  1076.     int xpreclip1    = horiz.clip.preclip;
  1077.     int xunclipped    = horiz.clip.unclipped;
  1078.     int xpostclip1    = horiz.clip.postclip;
  1079.     int xpostclip2    = horiz.clip.postclip2;
  1080.     int xpostcopy    = horiz.clip.postcopy;
  1081.     int xrightborder= xprecopy+xpreclip2+xpreclip1+xunclipped+xpostclip1+xpostclip2;
  1082.  
  1083.     int yprecopy    = vert.clip.precopy;
  1084.     int yinterp        = vert.clip.preclip + vert.clip.unclipped + vert.clip.postclip + vert.clip.allclip;
  1085.     int ypostcopy    = vert.clip.postcopy;
  1086.  
  1087.     __int64    xaccum    = horiz.u0_int.v;
  1088.     __int64    xinc    = horiz.dudx_int.v;
  1089.     __int64 yaccum    = vert.u0_int.v;
  1090.     __int64 yinc    = vert.dudx_int.v;
  1091.     int rowlastline = -1;
  1092.     int i, y;
  1093.  
  1094.     if (vert.clip.precopy || vert.clip.preclip || vert.clip.allclip) {
  1095.         srcp = src->Address32(0, 0);
  1096.  
  1097.         if (rows) {
  1098.             _DoRow(rowmem, srcp, src->w);
  1099.  
  1100.             for(i=0; i<rowcount*2; ++i)
  1101.                 rows[i] = rowmem;
  1102.  
  1103.             rowlastline = 0;
  1104.  
  1105.             if (vert.clip.precopy) {
  1106.                 for(y=0; y<yprecopy; ++y) {
  1107.                     memcpy(dstp, rowmem, 4*dx);
  1108.  
  1109.                     dstp = (Pixel32 *)((char *)dstp - dst->pitch);
  1110.                 }
  1111.             }
  1112.         } else {
  1113.             Pixel32 *dstp0 = dstp;
  1114.  
  1115.             _DoRow(dstp0, srcp, src->w);
  1116.  
  1117.             dstp = (Pixel32 *)((char *)dstp - dst->pitch);
  1118.  
  1119.             if (vert.clip.precopy) {
  1120.                 for(y=1; y<yprecopy; ++y) {
  1121.                     memcpy(dstp, dstp0, 4*dx);
  1122.  
  1123.                     dstp = (Pixel32 *)((char *)dstp - dst->pitch);
  1124.                 }
  1125.             }
  1126.         }
  1127.     }
  1128.  
  1129.     if (nHorizFilt == nVertFilt && nHorizFilt == eFilter::kPoint) {
  1130.         asm_resize_nearest(
  1131.                 dst->Address32(horiz.x1_int + horiz.clip.precopy + horiz.clip.unclipped, vert.x1_int + vert.clip.precopy),            // destination pointer, right side
  1132.                 src->Address32(horiz.u0_int.hi, vert.u0_int.hi),
  1133.                 -horiz.clip.unclipped*4,        // -width*4
  1134.                 vert.clip.unclipped,            // height
  1135.                 -dst->pitch,                    // dstpitch
  1136.                 -src->pitch,                    // srcpitch
  1137.                 horiz.u0_int.lo,                // xaccum
  1138.                 vert.u0_int.lo,                    // yaccum
  1139.                 horiz.dudx_int.lo,                // xfrac
  1140.                 vert.dudx_int.lo,                // yfrac
  1141.                 horiz.dudx_int.hi,                // xinc
  1142.                 -vert.dudx_int.hi * src->pitch,    // yinc
  1143.                 src->Address32(0, vert.u0_int.hi),
  1144.                 xprecopy,                        // precopy
  1145.                 src->Address32(src->w-1, vert.u0_int.hi),
  1146.                 xpostcopy                        // postcopy
  1147.                 );
  1148.  
  1149.         dstp = (Pixel32 *)((char *)dstp - dst->pitch * yinterp);
  1150.     } else if (nHorizFilt == nVertFilt && nHorizFilt == eFilter::kLinearInterp) {
  1151.         asm_resize_bilinear(
  1152.                 dst->Address32(horiz.x1_int + xprecopy + horiz.clip.unclipped, vert.x1_int + yprecopy),            // destination pointer, right side
  1153.                 src->Address32(horiz.u0_int.hi, vert.u0_int.hi),
  1154.                 -horiz.clip.unclipped*4,        // -width*4
  1155.                 vert.clip.unclipped,            // height
  1156.                 -dst->pitch,                    // dstpitch
  1157.                 -src->pitch,                    // srcpitch
  1158.                 horiz.u0_int.lo,                // xaccum
  1159.                 vert.u0_int.lo,                    // yaccum
  1160.                 horiz.dudx_int.lo,                // xfrac
  1161.                 vert.dudx_int.lo,                // yfrac
  1162.                 horiz.dudx_int.hi,                // xinc
  1163.                 -vert.dudx_int.hi * src->pitch,    // yinc
  1164.                 src->Address32(0, vert.u0_int.hi),
  1165.                 -xprecopy*4,                // precopy
  1166.                 src->Address32(src->w-1, vert.u0_int.hi),
  1167.                 -xpostcopy*4            // postcopy
  1168.                 );
  1169.  
  1170.         dstp = (Pixel32 *)((char *)dstp - dst->pitch * yinterp);
  1171.     } else
  1172.         for(y=0; y<yinterp; ++y) {
  1173.             long lastline = (long)(yaccum >> 32) + rowcount/2;
  1174.  
  1175.             if (rowlastline < lastline) {
  1176.                 int delta;
  1177.                 int pos;
  1178.  
  1179.                 if (rowlastline < lastline-rowcount)
  1180.                     rowlastline = lastline-rowcount;
  1181.  
  1182.                 delta = rowlastline - lastline;
  1183.  
  1184.                 srcp = src->Address32(0, rowlastline+1);
  1185.  
  1186.                 pos = rowlastline % rowcount;
  1187.  
  1188.                 do {
  1189.                     Pixel32 *row;
  1190.  
  1191.                     ++rowlastline;
  1192.                     if (++pos >= rowcount)
  1193.                         pos = 0;
  1194.  
  1195.                     if (rowlastline >= src->h) {
  1196.                         rows[pos] = rows[pos+rowcount] = rows[(pos+rowcount-1)%rowcount];
  1197.                         continue;
  1198.                     }
  1199.  
  1200.                     rows[pos] = rows[pos+rowcount] = rowmem + rowpitch * pos;
  1201.                     row = rows[pos];
  1202.  
  1203.                     _DoRow(row, srcp, src->w);
  1204.  
  1205.                     srcp = (Pixel32 *)((char *)srcp - src->pitch);
  1206.                 } while(++delta);
  1207.  
  1208.                 rowlastline = lastline;
  1209.             }
  1210.  
  1211.             int pos = (rowlastline+1) % rowcount;
  1212.  
  1213.             if (ytable)
  1214.                 resize_table_col(dstp, rows+pos, ytable, yfiltwidth, dx, ((unsigned long)yaccum>>24), 0);
  1215.             else switch(nVertFilt) {
  1216.                 case eFilter::kPoint:
  1217.                     memcpy(dstp, rows[pos], dx*4);
  1218.                     break;
  1219.                 case eFilter::kLinearInterp:
  1220.                     asm_resize_interp_col_run(
  1221.                             dstp,
  1222.                             rows[pos],
  1223.                             rows[pos+1],
  1224.                             dx,
  1225.                             (unsigned long)yaccum >> 16);
  1226.                     break;
  1227.                 case eFilter::kCubicInterp:
  1228.                     if (MMX_enabled)
  1229.                         asm_resize_ccint_col_MMX(dstp, rows[pos], rows[pos+1], rows[pos+2], rows[pos+3], dx, GetStandardCubic4Table()+1024+4*((unsigned long)yaccum>>24));
  1230.                     else
  1231.                         asm_resize_ccint_col(dstp, rows[pos], rows[pos+1], rows[pos+2], rows[pos+3], dx, GetStandardCubic4Table()+4*((unsigned long)yaccum>>24));
  1232.                     break;
  1233.             }
  1234.  
  1235.             yaccum += yinc;
  1236.             dstp = (Pixel32 *)((char *)dstp - dst->pitch);
  1237.         }
  1238.  
  1239.     if (vert.clip.postcopy) {
  1240.         srcp = dstp;
  1241.  
  1242.         _DoRow(dstp, src->Address32(0,src->h-1), src->w);
  1243.  
  1244.         for(y=1; y<ypostcopy; ++y) {
  1245.             dstp = (Pixel32 *)((char *)dstp - dst->pitch);
  1246.  
  1247.             memcpy(dstp, srcp, 4*horiz.dx_int);
  1248.         }
  1249.     }
  1250.  
  1251.     if (MMX_enabled)
  1252.         __asm emms
  1253.  
  1254.     stats_print();
  1255.  
  1256.     return true;
  1257. }
  1258.  
  1259. ///////////////////////////////////////////////////////////////////////////
  1260.  
  1261. static int permute_index(int a, int b) {
  1262.     return (b-(a>>8)-1) + (a&255)*b;
  1263. }
  1264.  
  1265. static void normalize_table(int *table, int filtwidth) {
  1266.     int i, j, v, v2;
  1267.  
  1268.     for(i=0; i<256*filtwidth; i+=filtwidth) {
  1269.         v=0;
  1270.         v2=0;
  1271.         for(j=0; j<filtwidth; j++)
  1272.             v += table[i+j];
  1273.  
  1274.         for(j=0; j<filtwidth; j++)
  1275.             v2 += table[i+j] = MulDiv(table[i+j], 0x4000, v);
  1276.  
  1277.         v2 = 0x4000 - v2;
  1278.  
  1279.         if (MMX_enabled) {
  1280.             for(j=0; j<filtwidth; j+=2) {
  1281.                 int a = table[i+j];
  1282.                 int b = table[i+j+1];
  1283.  
  1284.                 a = (a & 0xffff) | (b<<16);
  1285.  
  1286.                 table[i+j+0] = a;
  1287.                 table[i+j+1] = a;
  1288.             }
  1289.         }
  1290.  
  1291.         _RPT2(0,"table_error[%02x] = %04x\n", i, v2);
  1292.     }
  1293. }
  1294.  
  1295. int *Resampler::_CreateLinearDecimateTable(double dx, double sx, int& filtwidth) { 
  1296.     double filtwidth_fracd;
  1297.     long filtwidth_frac;
  1298.     double filt_max;
  1299.     int i;
  1300.     int *table;
  1301.  
  1302.     filtwidth_fracd = sx*256.0/dx;
  1303.  
  1304.     filtwidth_frac = (long)ceil(filtwidth_fracd);
  1305.     filtwidth = ((filtwidth_frac + 255) >> 8)<<1;
  1306.  
  1307.     if (!(table = new int[256 * filtwidth]))
  1308.         return NULL;
  1309.  
  1310.     table[filtwidth-1] = 0;
  1311.  
  1312.     filt_max = (dx*16384.0)/sx;
  1313.  
  1314.     for(i=0; i<128*filtwidth; i++) {
  1315.         int y = 0;
  1316.         double d = i / filtwidth_fracd;
  1317.  
  1318.         if (d<1.0)
  1319.             y = (int)(0.5 + filt_max*(1.0 - d));
  1320.  
  1321.         table[permute_index(128*filtwidth + i, filtwidth)]
  1322.             = table[permute_index(128*filtwidth - i, filtwidth)]
  1323.             = y;
  1324.     }
  1325.  
  1326.     normalize_table(table, filtwidth);
  1327.  
  1328.     return table;
  1329. }
  1330.  
  1331. int *Resampler::_CreateCubicDecimateTable(double dx, double sx, int& filtwidth) { 
  1332.     int i;
  1333.     long filtwidth_frac;
  1334.     double filtwidth_fracd;
  1335.     double filt_max;
  1336.     int *table;
  1337.  
  1338.     filtwidth_fracd = sx*256.0/dx;
  1339.     filtwidth_frac = (long)ceil(filtwidth_fracd);
  1340.     filtwidth = ((filtwidth_frac + 255) >> 8)<<2;
  1341.  
  1342.     if (!(table = new int[256 * filtwidth]))
  1343.         return NULL;
  1344.  
  1345.     table[filtwidth-1] = 0;
  1346.  
  1347.     filt_max = (dx*16384.0)/sx;
  1348.  
  1349.     for(i=0; i<128*filtwidth; i++) {
  1350.         int y = 0;
  1351.         double d = (double)i / filtwidth_fracd;
  1352.         const double A=-0.75;
  1353.  
  1354.         if (d < 1.0)
  1355.             y = (int)floor(0.5 + (1.0 - (A+3.0)*d*d + (A+2.0)*d*d*d) * filt_max);
  1356.         else if (d < 2.0)
  1357.             y = (int)floor(0.5 + (-4.0*A + 8.0*A*d - 5.0*A*d*d + A*d*d*d) * filt_max);
  1358.  
  1359.         table[permute_index(128*filtwidth + i, filtwidth)]
  1360.             = table[permute_index(128*filtwidth - i, filtwidth)]
  1361.             = y;
  1362.     }
  1363.  
  1364.     normalize_table(table, filtwidth);
  1365.  
  1366.     return table;
  1367. }
  1368.